package ru.ifmo.mlarinsky.classificator.providers;

import ru.ifmo.mlarinsky.classificator.io.IOUtil;

public class InstructionsProvider {

    public static final InstructionsProvider DEFAULTS =
            new InstructionsProvider() {

                private final UnsupportedOperationException onSetException =
                        new UnsupportedOperationException("It is forbidden to "
                        + "change defaults");

                @Override
                public VectorProvider getVectorProvider() {
                    return new DeterminationVectorProvider();
                }

                @Override
                public Format[] getFormats() {
                    return new Format[] {Format.SVG, Format.XML};
                }

                @Override
                public String getInputDataFile() {
                    return IOUtil.VECTORS_XML_FILE_PATH;
                }

                @Override
                public LatticeType getLatticeType() {
                    return LatticeType.RECTANGULAR;
                }

                @Override
                public double getLearningRate() {
                    return 0.01;
                }

                @Override
                public LearningRateType getLearningRateType() {
                    return LearningRateType.EXPONENTIAL;
                }

                @Override
                public NeighbourhoodType getNeighbourhoodType() {
                    return NeighbourhoodType.GAUSSIAN;
                }

                @Override
                public String getOutputMapFolder() {
                    return IOUtil.MAP_FOLDER;
                }

                @Override
                public int getRadius() {
                    return 11;
                }

                @Override
                public int getSteps() {
                    return 1000;
                }

                @Override
                public int getXDimension() {
                    return 20;
                }

                @Override
                public int getYDimension() {
                    return 20;
                }

                @Override
                public boolean isNormalizationUsed() {
                    return true;
                }

                @Override
                public String getOutputMapName() {
                    return "map";
                }

                @Override
                public void setVectorProvider(VectorProvider vectorProvider) {
                    throw onSetException;
                }

                @Override
                public void setOutputMapName(String outputMapName) {
                    throw onSetException;
                }

                @Override
                public void setFormats(Format... formats) {
                    throw onSetException;
                }

                @Override
                public void setInputDataFile(String inputDataFile) {
                    throw onSetException;
                }

                @Override
                public void setNormalizationUsed(boolean isNormalizationUsed) {
                    throw onSetException;
                }

                @Override
                public void setLatticeType(LatticeType latticeType) {
                    throw onSetException;
                }

                @Override
                public void setLearningRate(double learningRate) {
                    throw onSetException;
                }

                @Override
                public void setLearningRateType(LearningRateType learningRateType) {
                    throw onSetException;
                }

                @Override
                public void setNeighbourhoodType(NeighbourhoodType neighbourhoodType) {
                    throw onSetException;
                }

                @Override
                public void setOutputMapFolder(String outputMapFile) {
                    throw onSetException;
                }

                @Override
                public void setRadius(int radius) {
                    throw onSetException;
                }

                @Override
                public void setSteps(int steps) {
                    throw onSetException;
                }

                @Override
                public void setXDimension(int xDimension) {
                    throw onSetException;
                }

                @Override
                public void setYDimension(int yDimension) {
                    throw onSetException;
                }
            };
    private VectorProvider vectorProvider;
    private String inputDataFile;
    private String outputMapFolder;
    private String outputMapName;
    private boolean normalizationUsed;
    private int xDimension;
    private int yDimension;
    private int steps;
    private double learningRate;
    private int radius;
    private LatticeType latticeType;
    private NeighbourhoodType neighbourhoodType;
    private LearningRateType learningRateType;
    private Format[] formats;

    public VectorProvider getVectorProvider() {
        return vectorProvider;
    }

    public void setVectorProvider(VectorProvider vectorProvider) {
        this.vectorProvider = vectorProvider;
    }

    public Format[] getFormats() {
        return formats;
    }

    public void setFormats(Format... formats) {
        this.formats = formats;
    }

    public String getInputDataFile() {
        return inputDataFile;
    }

    public void setInputDataFile(String inputDataFile) {
        this.inputDataFile = inputDataFile;
    }

    public boolean isNormalizationUsed() {
        return normalizationUsed;
    }

    public void setNormalizationUsed(boolean isNormalizationUsed) {
        this.normalizationUsed = isNormalizationUsed;
    }

    public LatticeType getLatticeType() {
        return latticeType;
    }

    public void setLatticeType(LatticeType latticeType) {
        this.latticeType = latticeType;
    }

    public double getLearningRate() {
        return learningRate;
    }

    public void setLearningRate(double learningRate) {
        this.learningRate = learningRate;
    }

    public LearningRateType getLearningRateType() {
        return learningRateType;
    }

    public void setLearningRateType(LearningRateType learningRateType) {
        this.learningRateType = learningRateType;
    }

    public NeighbourhoodType getNeighbourhoodType() {
        return neighbourhoodType;
    }

    public void setNeighbourhoodType(NeighbourhoodType neighbourhoodType) {
        this.neighbourhoodType = neighbourhoodType;
    }

    public String getOutputMapName() {
        return outputMapName;
    }

    public void setOutputMapName(String outputMapName) {
        this.outputMapName = outputMapName;
    }

    public String getOutputMapFolder() {
        return outputMapFolder;
    }

    public void setOutputMapFolder(String outputMapFolder) {
        this.outputMapFolder = outputMapFolder;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public int getSteps() {
        return steps;
    }

    public void setSteps(int steps) {
        this.steps = steps;
    }

    public int getXDimension() {
        return xDimension;
    }

    public void setXDimension(int xDimension) {
        this.xDimension = xDimension;
    }

    public int getYDimension() {
        return yDimension;
    }

    public void setYDimension(int yDimension) {
        this.yDimension = yDimension;
    }

    @Override
    public String toString() {
        StringBuilder outputMapNamesBuilder = new StringBuilder();
        StringBuilder formatsBuilder = new StringBuilder();
        for (Format format : formats) {
            outputMapNamesBuilder.append("\toutputMapName = ").append(outputMapFolder).append(outputMapName).append(".").
                    append(format.stringValue).append("\n");
            formatsBuilder.append("\tformat = ").append(format.stringValue).append("\n");
        }

        return "instructions:\n" +
                "\tinputDataFile = " + inputDataFile + "\n" +
                outputMapNamesBuilder.toString() +
                "\toutputMapFolder = " + outputMapFolder + "\n" +
                "\toutputMapName = " + outputMapName + "\n" +
                formatsBuilder.toString() +
                "\tnormalizationUsed = " + normalizationUsed + "\n" +
                "\txDimension = " + xDimension + "\n" +
                "\tyDimension = " + yDimension + "\n" +
                "\tradius = " + radius + "\n" +
                "\tsteps = " + steps + "\n" +
                "\tlearningRate = " + learningRate + "\n" +
                "\tlearningRateType = " + learningRateType + "\n" +
                "\tlatticeType = " + latticeType + "\n" +
                "\tneighbourhoodType = " + neighbourhoodType + "\n";
    }

    public enum Format {

        XML("xml"),
        SVG("svg");
        private final String stringValue;

        private Format(String stringValue) {
            this.stringValue = stringValue;
        }

        @Override
        public String toString() {
            return stringValue;
        }
    }

    public enum LearningRateType {

        EXPONENTIAL("exponential"),
        LINEAR("linear"),
        INVERSE("inverse");
        private final String stringValue;

        private LearningRateType(String stringValue) {
            this.stringValue = stringValue;
        }

        @Override
        public String toString() {
            return stringValue;
        }
    }

    public enum LatticeType {

        HEXAGONAL("hexagonal"),
        RECTANGULAR("rectangular");
        private final String stringValue;

        private LatticeType(String stringValue) {
            this.stringValue = stringValue;
        }

        @Override
        public String toString() {
            return stringValue;
        }
    }

    public enum NeighbourhoodType {

        GAUSSIAN("gaussian"),
        STEP("step");
        private final String stringValue;

        private NeighbourhoodType(String stringValue) {
            this.stringValue = stringValue;
        }

        @Override
        public String toString() {
            return stringValue;
        }
    }
}
